
#include "StdAfx.h"
#include "profiler.h"
#include <stdio.h>
#include <stdlib.h>

#ifdef WIN32
#include <time.h>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "Winmm.lib")
#endif

#include <Log.h>

Profiler::Profiler(){	
	m_startProfile = 0.f;
	m_endProfile   = 0.f;		
}

Profiler::~Profiler(){}

void Profiler::initialize(){
    for( int i=0; i < NUM_PROFILE_SAMPLES ; i++ ) {
      m_samples[i].bValid = false;
      m_history[i].bValid = false;
    }

    m_startProfile = ((float)timeGetTime())/1000.0f;
}

void Profiler::startProfile(char * strName){	
    unsigned int i = 0;

	while( i < NUM_PROFILE_SAMPLES && m_samples[i].bValid == true ) {
        if( strcmp( m_samples[i].szName, strName ) == 0 ) {            
			m_samples[i].iOpenProfiles++;
			m_samples[i].iProfileInstances++;
			m_samples[i].fStartTime = ((float)timeGetTime())/1000.0f;

			return;
		}

		i++;	
	}

	if( i >= NUM_PROFILE_SAMPLES )
		return;

	strcpy( m_samples[i].szName, strName );

	m_samples[i].bValid = true;
	m_samples[i].iOpenProfiles = 1;
	m_samples[i].iProfileInstances = 1;
	m_samples[i].fAccumulator = 0.0f;
	m_samples[i].fStartTime = ((float)timeGetTime())/1000.0f;
	m_samples[i].fChildrenSampleTime = 0.0f;
	m_samples[i].parentsNum = -1;
}

void Profiler::endProfile(char * strName){	
   unsigned int i = 0;
   unsigned int numParents = 0;

   while( i < NUM_PROFILE_SAMPLES && m_samples[i].bValid == true ){
      if( strcmp( m_samples[i].szName, strName ) == 0 ){  //Found the sample
         unsigned int inner = 0;
         int parent = -1;
         float fEndTime = ((float)timeGetTime())/1000.0f;
         m_samples[i].iOpenProfiles--;

         //Count all parents and find the immediate parent
         while( m_samples[inner].bValid == true ) {
            if( m_samples[inner].iOpenProfiles > 0 ){  //Found a parent (any open profiles are parents)
               numParents++;

               if( parent < 0 )//Replace invalid parent (index)
                  parent = inner;               
               else if( m_samples[inner].fStartTime >= m_samples[parent].fStartTime )//Replace with more immediate parent
                  parent = inner;               
            }

            inner++;
         }

         //Remember the current number of parents of the sample
         m_samples[i].iNumParents = numParents;

         if( parent >= 0 ){  //Record this time in fChildrenSampleTime (add it in)
            m_samples[parent].fChildrenSampleTime += fEndTime - m_samples[i].fStartTime;

			//m_samples[i].parantsName.push_back(m_samples[parent].szName);
			m_samples[i].parentsNum = parent;
         }

         //Save sample time in accumulator
         m_samples[i].fAccumulator += fEndTime - m_samples[i].fStartTime;

         return;
      }

      i++;	
   }
}

void Profiler::writeResult(){
	unsigned int i = 0;
    m_endProfile = ((float)timeGetTime()) / 1000.0f;

    CLog log( 2, ".\\xp_db_bridge_profile.txt", 0, 0, 0 );	
    log.Log("  Ave :   Min :   Max :   # : Profile Name ");
    log.Log("-------------------------------------------- ");

    while( i < NUM_PROFILE_SAMPLES && m_samples[i].bValid == true ) {		
        unsigned int indent = 0;
		float sampleTime, percentTime, aveTime, minTime, maxTime;
		char line[256], name[256], indentedName[256];
		char ave[16], min[16], max[16], num[16];

        if( m_samples[i].iOpenProfiles < 0 )
			return;
		else if( m_samples[i].iOpenProfiles > 0 ) 
			return;

		sampleTime = m_samples[i].fAccumulator - m_samples[i].fChildrenSampleTime;
		percentTime = ( sampleTime / (m_endProfile - m_startProfile ) ) * 100.0f;

		aveTime = minTime = maxTime = percentTime;

		//Add new measurement into the history and get the ave, min, and max
		storeProfileInHistory( m_samples[i].szName, percentTime );
		getProfileFromHistory( m_samples[i].szName, &aveTime, &minTime, &maxTime );

		//Format the data
		sprintf( ave, "%3.1f", aveTime );
		sprintf( min, "%3.1f", minTime );
		sprintf( max, "%3.1f", maxTime );
		sprintf( num, "%6d", m_samples[i].iProfileInstances );

		strcpy( indentedName, m_samples[i].szName );

		ProfileSample *parents;

		if( m_samples[i].iNumParents > 0 )
			parents = &(m_samples[ m_samples[i].parentsNum ]);

		for( indent=0; indent<m_samples[i].iNumParents; indent++ ) {
			sprintf( name, "  %s::  %s", parents->szName , indentedName );
			strcpy( indentedName, name );
			
			parents = &(m_samples[ parents->parentsNum ]);
		}

		sprintf(line,"%5s : %5s : %5s : %6s : %s", ave, min, max, num, indentedName);		
		log.Log(line);		
		i++;
	}	

	{  //Reset samples for next frame
		for( unsigned int i = 0 ; i < NUM_PROFILE_SAMPLES ; i++ )
			m_samples[i].bValid = false;

		m_startProfile = ((float)timeGetTime())/1000.0f;
	}	
}

void Profiler::storeProfileInHistory( char* name, float percent ){
   unsigned int i = 0;
   float oldRatio;
   float newRatio = 0.8f * (((float)timeGetTime())/1000.0f);

   if( newRatio > 1.0f )
      newRatio = 1.0f;
   
   oldRatio = 1.0f - newRatio;

   while( i < NUM_PROFILE_SAMPLES && m_history[i].bValid == true ) {
      if( strcmp( m_history[i].szName, name ) == 0 ){  //Found the sample
         m_history[i].fAve = (m_history[i].fAve*oldRatio) + (percent*newRatio);

         if( percent < m_history[i].fMin )
            m_history[i].fMin = percent;         
         else
            m_history[i].fMin = (m_history[i].fMin*oldRatio) + (percent*newRatio);         

         if( m_history[i].fMin < 0.0f )
            m_history[i].fMin = 0.0f;		 

         if( percent > m_history[i].fMax )
            m_history[i].fMax = percent;         
         else
            m_history[i].fMax = (m_history[i].fMax*oldRatio) + (percent*newRatio);
         
         return;
      }

      i++;
   }

   if( i < NUM_PROFILE_SAMPLES ){  //Add to history
      strcpy( m_history[i].szName, name );
      m_history[i].bValid = true;
      m_history[i].fAve = m_history[i].fMin = m_history[i].fMax = percent;
   }
   else
       return;   
}

void Profiler::getProfileFromHistory( char* name, float* ave, float* min, float* max ){
   unsigned int i = 0;

   while( i < NUM_PROFILE_SAMPLES && m_history[i].bValid == true ) {
      if( strcmp( m_history[i].szName, name ) == 0 ){  //Found the sample
         *ave = m_history[i].fAve;
         *min = m_history[i].fMin;
         *max = m_history[i].fMax;

         return;
	  }

      i++;
   }	

   *ave = *min = *max = 0.0f;
}
